﻿#pragma execution_character_set("utf-8")//可视化内容
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QPixmap>
#include <QGroupBox>
#include <QComboBox>
#include <QPushButton>
#include <findway.h>

bool MainWindow::drawPath(QVector<int> path)
{
    //QGraphicsPathItem 是 Qt 的图形视图框架中的一个类，用于表示一个可以在 QGraphicsScene 中绘制的路径项
    //QGraphicsPathItem 可以响应鼠标事件、键盘事件等，使得可以与用户进行交互
    QGraphicsPathItem *item = new QGraphicsPathItem();

    //创建画笔对象，设置路径绘制的线条的宽度和颜色
    QPen pen;

    //根据不同的人行道和自行车道绘制不同的线条
    switch (waykind) {
    case 0:
        pen.setWidth (10);
        pen.setColor (Qt::blue);
        break;
    case 1:
        pen.setWidth (12);
        pen.setColor (Qt::green);
        break;
    default:
        break;
    }
    //将设置好的Pen应用到这个图形当中
    item->setPen (pen);

    //QGraphicsItem::ItemIsPanel 是一个特定的标志，表示该图形项作为面板使用
    //item 会在其子项之下绘制，并且不会响应鼠标事件，从而不干扰其它图形项的交互。
    item->setFlag (QGraphicsItem::ItemIsPanel);

    //创建一个 QPainterPath 对象，pa 是一个绘制路径的对象，可以用来存储一系列的路径段，他规定了路径的形状走势即几何形状
    QPainterPath pa;

    //创建两个 QPixmap 对象，分别从资源文件中加载图像
    QPixmap startPixMap(":/images/images/startImages.png");   //插入起点图片
    QPixmap endPixMap(":/images/images/endImages.png");       //插入终点图片

    //QPixmap 是一个 Qt 类，用于表示图像，并在 QGraphicsView 等图形界面中展示

    //QGraphicsPixmapItem 是 Qt 的一个图形项类
    //将QPixmap startPixMap endPixMap加载的图片添加到QGraphicsScene地图中
    startPixMapItem = new QGraphicsPixmapItem(startPixMap);
    endPixMapItem = new QGraphicsPixmapItem(endPixMap);

    //moveTo 方法是 QPainterPath 类中的一个函数 将当前绘图路径的起始点移动到指定的位置
    pa.moveTo (pointList[startPointIndex].x,pointList[startPointIndex].y);//设置起点

    //遍历findway当中的Path(存放起点到某个顶点之间的最短路径的前驱结点数组)
    //从i=1开始遍历，因为i=0的情况是起点刚刚设置好的
    for (int i=1;i<path.size();i++)
    {
        pa.lineTo (pointList[path[i]-1].x,pointList[path[i]-1].y);//用lineTo方法绘制最短路径的线段
    }

    //将刚刚的QPainterPath类对象 pa设置为QPainterPath类对象 item的路径
    item->setPath (pa);

    //将路径显示在图形item当中
    scene->addItem (item);

    //起点、终点的图像项 startPixMapItem endPixMapItem添加到item中
    scene->addItem(startPixMapItem);
    scene->addItem(endPixMapItem);

    //设置结束点图标的偏移量。setOffset 用于调整图标的位置，使其位于路径的最后一个点上，并向上偏移 33 个像素。
    //这里的 path[path.size()-1] 是路径数组中的最后一个索引，表示结束点。
    endPixMapItem->setOffset(pointList[path[path.size()-1]-1].x,pointList[path[path.size()-1]-1].y -33);

    //设置起始点图标的偏移量，使其位于起始点的坐标位置，并向上偏移 33 个像素
    startPixMapItem->setOffset(pointList[startPointIndex].x,pointList[startPointIndex].y -33);

    isclear = false;//表示当前状态不是清空状态


    return true;
}

//初始化图形视图及其场景
void MainWindow::initQGraphics()
{
    resize(1550,810);
    //这个是主窗口

    ui->graphicsView->setMinimumSize(1350, 810);
    //这个是地图窗口

    QImage image(":/images/images/map.jpg");
    //加载地图图片文件

    scene = new QGraphicsScene();
    //创建一个新的 QGraphicsScene 对象并将其指针赋值给 scene
    //QGraphicsScene 是一个容器，用于管理和存储多个图形项（QGraphicsItem）。它负责处理图形项的渲染、事件处理和交互
    item = new QGraphicsPixmapItem;
    //创建一个新的 QGraphicsPixmapItem 对象并将其指针赋值给 item
    //GraphicsPixmapItem 是一个具体的图形项，用于在场景中显示位图图像。

    item = scene->addPixmap(QPixmap::fromImage(image));
    //将图像image作为图形项添加到场景中

    ui->graphicsView->setScene(scene);
    //将创建的 scene 设置为图形视图 graphicsView 的场景

    ui->graphicsView->show();//显示图形
    //QGraphicsScene 是一个管理多个图形项的容器，负责处理它们的布局和事件，而 QGraphicsPixmapItem 是一种具体的图形项，专门用于显示图像。
}

//这个函数主要是处理路径查找的逻辑，包括加载起止点图像、调用路径查找算法、绘制路径
void MainWindow::findPath()
{
    //加载起点和终点的图片
    QPixmap startpixmap(":/images/images/start.png");
    QPixmap endpixmap(":/images/images/end.png");

    //将加载的图片设置到对应的项上
    position[startPointIndex]->setPixmap(startpixmap);
    position[endPointIndex]->setPixmap(endpixmap);

    //创建一个路径对象
    Path path;
    path = way->findPath(startPointIndex + 1,endPointIndex + 1,waykind);  //调用了之前findway（）寻找最小路径函数

    if(path.path == QVector<int>(0)) return;//如果路径为空 不执行

    //如果场景没有刷新 刷新地图
    if(!isclear) reset();

    //调用drawpath函数绘制路径
    drawPath(path.path);

    //更新状态为4 前面选择完起始点和终点停留在step = 4
    step = 4;

    //路径播报功能 （文本输出）
     speech(path);

}

 // 定义设置起始点的函数
void MainWindow::setStart(int startindex)
{
    QPixmap startpixmap(":/images/images/start.png");  // 创建起始点图像对象
    position[startindex]->setPixmap(startpixmap);  // 将起始点图像设置到对应的项上
    startPointIndex = startindex;  // 更新起始点索引
    qDebug() << "startPointIndex:" << startPointIndex;
}

// 定义设置结束点的函数
void MainWindow::setEnd(int endindex)
{
    QPixmap endpixmap(":/images/images/end.png");  // 创建结束点图像对象
    position[endindex]->setPixmap(endpixmap);  // 将结束点图像设置到对应的项上
    endPointIndex = endindex;  // 更新结束点索引
    qDebug() << "endPointIndex:" << endPointIndex;
}

//定义刷新地图的函数，就是重新加载路径点
void MainWindow::reset()
{
    //加载路径点图片
    QPixmap pospixmap(":/images/images/position.png");
    FindWay findway;
    //重新放置路径点到规定的位置
    position[ui->endComboBox->currentIndex()]->setPixmap(pospixmap);
    position[ui->startComboBox->currentIndex()]->setPixmap(pospixmap);

    //清除的逻辑控制
    if(!isclear){

        //清除路径 起点 终点
        scene->removeItem(scene->items()[0]);
        scene->removeItem(scene->items()[0]);
        scene->removeItem(scene->items()[0]);
        qDebug()<<scene->items()[0];

        //停止语音播报
        findway.stopspeek();

        //清除导航播报的文本
        ui->actBrowser->clear();

        //更新为清除状态
        isclear = true;

        //步骤为1
        step = 1;
    }
}

//设置路径类型的函数
void MainWindow::setway()
{
    //获取下拉选择框的类型索引赋给waykind
    waykind = ui->wayComboBox->currentIndex();
}

// 处理用户在图形视图中选择的项，根据当前步骤设置起始点或结束点的图标，同时支持状态重置。通过这种方式，用户可以直观地选择路径的起点和终点。
void MainWindow::chooseItem(QGraphicsItem *Pixmapitem) //定义选择图形项的函数，参数为图形项指针
{
    // 加载起始点、结束点和路径点的图标
    QPixmap startpixmap(":/images/images/start.png"); // 起始点图标
    QPixmap endpixmap(":/images/images/end.png");     // 结束点图标
    QPixmap pospixmap(":/images/images/position.png"); // 路径点图标

    // 遍历所有可能的图形项
    for(int i = 0; i < 100; i++) {
        if(Pixmapitem == position[i]) { // 如果当前选择的图形项与某个位置项匹配
            if(step == 1) { // 如果当前步骤是1，设置起始点
                ui->startComboBox->setCurrentIndex(position[i]->getindex()); // 更新下拉框索引
                startPointIndex = position[i]->getindex(); // 记录起始点索引
                position[i]->setPixmap(startpixmap); // 将当前项设置为起始点图标
                step = 2; // 更新步骤为2
            }
            else if (step == 2 || step == 3) { // 如果步骤是2或3，设置结束点
                position[ui->endComboBox->currentIndex()]->setPixmap(pospixmap); // 恢复之前的结束点图标
                ui->endComboBox->setCurrentIndex(position[i]->getindex()); // 更新下拉框索引为新结束点
                endPointIndex = position[i]->getindex(); // 记录结束点索引
                position[i]->setPixmap(endpixmap); // 将当前项设置为结束点图标
                step = 3; // 更新步骤为3
            } else if (step == 4)
            {
                // 如果步骤是4，重置状态
                reset();
            }
        }
    }
}

//函数接收到Path类的path变量其中包含了路径和距离 就是ppt上的PATH DIST
void MainWindow::speech(Path path)
{
    //最后输出的文本
    QString text ;
    //当前路径段的文本
    QString sequence;
    //当前路径段的距离
    int dist = 0;
    //计数器
    int i;
    //计算总距离
    int totaldist = 0;
    FindWay findWay;
    sequence.append("从"+ui->endComboBox->itemText(path.path[0]-1)+"前进");
    qDebug()<<sequence;

    dist = path.distance[0];

    for (i=1;i<path.path.size()-1;i++){

        if(ui->endComboBox->itemText(path.path[i]-1)==""){
            dist = dist + path.distance[i];
        }
        else{
        sequence.append(QString::number(dist)+"米,到达"+ui->endComboBox->itemText(path.path[i]-1)+"。");
        totaldist = totaldist + dist;
        dist = path.distance[i];
        text.append(sequence);
        ui->actBrowser->append(sequence);
        sequence.clear();
        sequence.append("再从"+ui->endComboBox->itemText(path.path[i]-1)+"前进");
        }
        qDebug()<<text;
        qDebug()<<ui->endComboBox->itemText(path.path[i]);

    }
    sequence.append(QString::number(dist)+"米,到达终点"+ui->endComboBox->itemText(path.path[i]-1)+"。");
    totaldist = totaldist + dist;
    if(ui->wayComboBox->currentIndex() == 0){
        text.append(sequence+"此行程共计"+QString::number(totaldist)+"m,预计花费时间"+QString::number(totaldist/80)+"分钟");
        ui->actBrowser->append(sequence+"\n"+"此行程共计"+QString::number(totaldist)+"m,预计花费时间"+QString::number(totaldist/80)+"分钟");
    }else {
        text.append(sequence+"此行程共计"+QString::number(totaldist)+"m,预计花费时间"+QString::number(totaldist/200)+"分钟");
        ui->actBrowser->append(sequence+"\n"+"此行程共计"+QString::number(totaldist)+"m,预计花费时间"+QString::number(totaldist/200)+"分钟");
    }
    findWay.speek(text.toLocal8Bit().data());
    qDebug()<<text;
}

void MainWindow::on_mouseMovePoint(QPointF viewPoint, QPointF scenePoint)
{
    labViewCord->setText(QString::asprintf("view坐标:%.0f,%.0f", viewPoint.x(), viewPoint.y()));
    labSceneCord->setText(QString::asprintf("scene坐标:%.0f,%.0f", scenePoint.x(),scenePoint.y()));
}

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    endPointIndex = 0;
    startPointIndex = 0;
    waykind = 0;
    step = 1;
    labViewCord = new QLabel("view坐标:");
    labSceneCord = new QLabel("scene坐标:");
    ui->statusBar->addWidget(labViewCord);
    ui->statusBar->addWidget(labSceneCord);
    isclear = true;

    way = new FindWay();
    int pointx[MAX_VERTEX_NUM-1]={ 228,  454,  598,  569,  977, 1169,  438,  405,  289,  284,
                                   285,  295,  301,  299,  597,  706,  758,  728,  451,  783,
                                   451,  751,  589,  570,  513,  690, 872, 1211, 1313, 1397,
                                  1366, 1130, 1125, 1131, 1418, 1265, 1496, 1532, 1526, 1211,
                                  1486, 1703, 1873, 2065, 2217, 1951, 1880, 1959, 2029, 1646,

                                  1593, 1630, 1703, 1778, 1850, 1651, 2257, 2425, 2387, 2350,
                                  2280, 2197, 2152, 2333, 2329, 2359, 2128, 2264, 2583, 2977,
                                  2974, 2978, 2997, 2977, 2976, 2747, 2897, 2757, 3182, 3039,
                                  1799, 2084, 2574, 2881, 2974, 3057, 3105,  458,  458,  458,
                                   316,  170,  389,  113,  174,  589,  664,  175, 1064, 1380,

                                  456,   634, 1160, 1265, 1122,  832,  615,  292,  905,  579,
                                  593,   589,  608,  603,  860,  845,  839, 1024, 1206, 1256,
                                  1419, 1013,  864,  910,  860, 1457,  852,  881,  750, 1388,
                                  1301,  1622, 1523, 1704, 1704, 1867, 1602, 1598, 1867, 1708,
                                  1876, 1880, 1974, 1979, 2211, 1703, 1865, 1799, 2066, 1757,

                                  1834, 1909, 2215, 2055, 2443, 1433, 1692, 1697, 1789, 1845,
                                  1740, 1888, 2051, 1658, 2186, 2306, 2041, 2043, 2139, 2110,
                                  2194, 2173, 2274, 2363, 2248, 2976, 2878, 2898, 2898, 2898,
                                  3026, 2755, 2896, 3090, 3221, 3119, 2966, 1609,  120,  311,
                                   598,  588,  464, 959,  1126, 402,  442,  442,  664,  306,

                                   392,  702,  682, 1158, 1478, 1366,  849, 2250, 845};

    int pointy[MAX_VERTEX_NUM-1]={ 337,  268,  215,  150,  229,  225,  639,  679,  802,  943,
                                   992, 1193, 1358, 1445, 1440, 1339, 1250, 1149, 1114, 1071,
                                  1011,  983,  884,  797,  712,  396,  567,  486,  668,  416,
                                   769,  786,  691, 1229, 1283, 1441, 1258, 1348, 1473, 1107,
                                   344,  494,  525,  698,  690,  999, 1126, 1271, 1376, 1605,

                                  1810, 1883, 2008, 2137, 2264, 2402, 2208, 2071, 2001, 1933,
                                  1802, 1678, 1591, 1365, 1429, 1514, 2705, 2614,  858,  246,
                                   467,  637,  956, 1193, 1305, 1973, 2039, 2108, 2044, 2462,
                                   865, 1480, 2041, 1557, 1562, 1916, 1812, 2690, 2615, 2477,
                                  2370, 2370, 2231, 1624, 1472, 1646, 1759, 2487, 2551, 2302,

                                   303,  273,  422,  586,  588,  377, 1014, 1118, 1146, 1122,
                                  1190, 1158, 1269, 1341, 1250, 1338, 1441, 1430,  914,  910,
                                   868, 1013,  710,  816,  850, 1374,  246,  369,  575, 1473,
                                  1050, 1400,  331,  335,  387,  225,  212,  235,  383,  678,
                                   680,  625,  624,  684,  373,  868,  877,  980,  883, 1267,

                                  1398, 1544,  875, 1168, 2366, 1568, 1710, 1887, 2029, 2153,
                                  2079, 2308, 2572, 2583, 2246, 2459, 1799, 1803, 1762, 1937,
                                  1898, 2070, 2014, 1690, 1754,  863, 1240, 1992, 2105, 2274,
                                  2301, 2037, 1814, 2178, 2323, 1898, 1808, 2150, 1473, 1490,
                                  1495, 1756, 2376, 1844, 2025, 1802, 1864, 1864, 1859, 1627,

                                  2371, 2304, 2370, 2398, 2587, 2156, 1029, 1754, 1495};
    pointList[MAX_VERTEX_NUM-1];
    for (int i = 0; i < MAX_VERTEX_NUM-1; ++i) {
        pointList[i].x = pointx[i];
        pointList[i].y = pointy[i];

    }

    connect(ui->resetButton, SIGNAL(clicked()), this, SLOT(reset()));
    connect(ui->endComboBox, SIGNAL(activated(int)), this, SLOT(setEnd(int)));
    connect(ui->wayComboBox, SIGNAL(activated(int)), this, SLOT(setway()));
    connect(ui->graphicsView,SIGNAL(item(QGraphicsItem*)),this, SLOT(chooseItem(QGraphicsItem*)));
    connect(ui->startComboBox, SIGNAL(activated(int)), this, SLOT(setStart(int)));
    connect(ui->findPathButton, SIGNAL(clicked()), this, SLOT(findPath()));

    QObject::connect(ui->graphicsView, SIGNAL(mouseMovePoint(QPointF, QPointF)),
                     this, SLOT(on_mouseMovePoint(QPointF, QPointF)));

    initQGraphics();
    QPixmap point(":/images/images/position.png");
    for (int i= 0;i<100;i++){
        position[i] = new my_pixmapitem();
        position[i]->setPixmap(point);
        position[i]->setindex(i);
        scene->addItem(position[i]);
        position[i]->setOffset(pointList[i].x-50,pointList[i].y-100);
        qDebug()<<"position"<<position[i];
    }
    ui->graphicsView->setCursor(Qt::CrossCursor);
    ui->graphicsView->setMouseTracking(true);

}

MainWindow::~MainWindow()
{
    delete ui;
}
